#ifndef CLASSE_H
#define CLASSE_H

#include <iostream>
#include <vector>
#include <map>
#include "debugstreams.h"
#include "lib.h"

#include <boost/assign/list_of.hpp>

using namespace std;

//typedef vector< unsigned int > colonne;

/**
 * La classe Classe représente une classe au sens AD&D. C'est une classe
 * abstraite, qui sert au polymorphisme.
 * @author Johan "Solo" Luisier
 */
class Classe
{
 protected:
  /**
   * Nom des traits.
   */
  static string Caracteristiques[6];
  /**
   * Niveau, niveau magique et nombre de pts d'expérience.
   */
  unsigned int Niveau, Niveau_mag, XP;
  /**
   * Valeurs des traits du personnage, le 7ème contient le score de
   * force exceptionnel (0 si non applicable).
   */
  unsigned int Traits[7];
  /**
   * Nom de la classe ("Rôdeur", "Barde", ...).
   */
  string Type_classe;
  /**
   * Liste des compétences de classe.
   */
  vector<unsigned int> Comp_classe;
  /**
   * Liste des sorts du livre de sort (Mages, Spécialistes et Bardes
   * uniquement).
   */
  vector<Sort> Cl_sorts;
  /**
   * Type de classe (TypeClasse) disponibles, détermine les compétences
   * non-martiales accessibles.
   * @see TypeClasse
   */
  vector<TypeClasse> TC;
  static DebugLevelType elementaire, /**< Niveau de sortie des fonctions globales  @see DebugLevelType @see debugstream */
    fonction; /**< Niveau de sortie des fonctions plus spécifiques de Classe @see DebugLevelType @see debugstream */
  const vector<ListComp>
    *ptrComp, /**< Pointeur sur les compétences de classe */
    *ptrRes;/**< Pointeur sur les restrictions */
  /**
   * Pointe sur le conteneur des valeurs de base des compétences associées
   * à un pourcentage (voleur, bardes)
   */
  const vector<unsigned int> *ptrValBase;
  const unsigned int *ptrNbrComp, /**< Pointeur sur le nombre de compétences */
    *ptrNbrRes; /**< Pointeur sur le nombre de restrictions */
 public:

  Classe();
  Classe(unsigned int xp, unsigned int trait[7], TypeClasse tc);
  Classe(const Classe& classe);
  virtual ~Classe();
  void set_Competences(const vector<unsigned int> capa);
  void affiche() const;
  /**
   * Calcule le niveau du personnage, en fonction de sa classe et de son
   * nombre de pts d'expérience.
   */
  virtual void calcul_niveau() = 0;
  void afficher_stats(ostream& os = blank());
  void affiche_competences(ostream& os = blank()) const;
  string get_classe() const;
  unsigned int get_XP() const;
  unsigned int get_trait(const unsigned int& i) const;
  unsigned int get_combien() const;
  unsigned int get_comp(const unsigned int& i) const;
  /**
   * Applique les ajustements raciaux aux compétences de classe. Ne
   * touche que les talents de voleur et de barde
   * @param type le nom de la race du personnage
   */
  virtual void appliquer_modif(const string& type) = 0;
  /**
   * Distribue les points pour les compétences liées à un pourcentage
   * lors de la création ou du passage de niveau
   * @param bonus nombre de points à dépenser
   * @param lvl_up true si passage de niveau
   */
  virtual void augmenter_talents(const unsigned int& bonus,
				 const bool& lvl_up) = 0;
  /**
   * Calcule les JS du personnage et les mets dans le tableau passé en argument.
   * Si le personnage a plusieurs classes, les JS les plus avantageux seront
   * automatiquement sélectionnés dans la classe Joueur.
   * @param tab pointeur sur le tableau contenant les JS.
   */
  virtual void get_JS(unsigned int *tab) const = 0;
  /**
   * Retrouve la compétence désirée.
   * @param i numéro de la compétence
   * @return string de la compétence voulue, avec le pourcentage éventuellement
   * associé.
   */
  string get_competence(const unsigned int& i) const;
  /**
   * Permet de récupérer la valeur de base du pourcentage associé
   * à une compétence
   * @param i numéro de la compétence
   * @return valeur de base de la compétence
   */
  virtual unsigned int get_valeur_base(const unsigned int& i) const;
  /**
   * Permet de récupérer le niveau du personnage (qui n'est pas accessible
   * depuis l'extérieur).
   * @return niveau du personage (pour la classe considérée).
   */
  unsigned int get_Niveau() const;
  /**
   * Permet de récupérer le niveau de magie du personnage (qui n'est pas
   * accessible depuis l'extérieur).
   * @return niveau du personage (pour la classe considérée).
   */
  unsigned int get_Niveau_magie() const;
  /**
   * Calcule le TAC0 du personnage
   */
  virtual unsigned int calcule_TAc0() const = 0;
  /**
   * Calcule le niveau de magie du personnage, en fonction de sa classe
   * et de son niveau (recalculé par précaution). Si le personnage n'a pas
   * de sorts ou a un niveau insuffisant pour en lancer, le niveau magique
   * calculé est 0.
   */
  virtual void calcul_niv_mag() = 0;
  /**
   * Ecrit le fichier qui contient les sorts que connait le personnage
   * @param nom_fichier nom du fichier à écrire
   * @param ecrase (dés)active l'écrasement du fichier (si false, on
   * ajoutte les sorts à la suite du fichier nom_fichier).
   */
  virtual void ecrire_sorts(const string& nom_fichier, const bool& ecrase) const = 0;
  /**
   * Récupère le nombre de sorts de chaque niveau que peut lancer le personnage.
   * @param sorts[] est le tableau qui contiendra les nombres de sorts.
   * @param taille est la taille de sorts, qui correspond au niveau de magie.
   */
  virtual void nbr_sort(unsigned int sorts[], const unsigned int& taille) const = 0;
  string supprime_accents(const string& brut) const;
  const vector<TypeClasse>* get_TC() const;
  void augmenter_xp(const unsigned int& xp);
  static void setLevel(const DebugLevelType& level, const unsigned int& n);
  virtual void ajout_sorts();
  void ajout_sorts(const vector<Sort>& vec);
  void set_Sorts(const vector<Sort>& sorts);
  void set_xp(const unsigned int& xp);
  unsigned int get_combien_sorts() const;
  Sort get_sort(const unsigned int& i) const;
  const vector<Sort>* get_sort_adresse() const;
  void get_competences(unsigned int& nbrComp, vector<ListComp>& comp, unsigned int& nbrRes, vector<ListComp>& restric) const;
  virtual void get_ensembles_capacites(unsigned int& nbr, unsigned int& max) const;
  virtual const unsigned int* get_ensembles_capacites(const unsigned int& nbr) const;
  virtual const string* get_nom_ensemble(const unsigned int& nbr) const;
  unsigned int get_PP() const;
  /**
   * Fait correspondre le prix d'accès à une compétence martiale en fonction
   * de la classe du personnage.
   * @param Map pointeur sur la map qui sera la table de correspondance.
   */
  virtual void get_prix_acces(map<string, unsigned int>* Map) const = 0;
  /**
   * Retrouve les compétences et restrictions de la classe. Les numéros
   * de ces compétences sont retournées.
   * @param vec le conteneur où seront stockés les numéros
   */
  const vector<unsigned int>* get_toutes_competences(unsigned int& nbr) const;
  void prepare_affichage();
  ListComp get_competence_numero(const unsigned int& i) const;
  bool possede_pourcent() const;
  virtual unsigned int get_pourcent(const bool& lvlUp) const;
};

#endif
